﻿using DevExpress.XtraEditors.Controls;
using DevExpress.XtraEditors.Repository;
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;

namespace TIMA.DevTeam
{
    public static class FabricManager
    {
        public static DataTable ProductsKarbel = null;
        
        public static string AppDataPath = Directory.CreateDirectory(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TIMA")).FullName;
        public static string FabricManagerFileName = Path.Combine(AppDataPath, "FabricManager.dat");        
        public static Dictionary<int, double[]> AllFeatures = new Dictionary<int, double[]>();
        public static Dictionary<int, double[]> KarbelFeatures = new Dictionary<int, double[]>();
        public static Dictionary<int, double[]> MontiFeatures = new Dictionary<int, double[]>();

        public static void Init()
        {
            ProductsKarbel = GetLocalPhotos();

            RefreshFeatures();
        }

        public static void RefreshFeatures()
        {
            FabricManager.AllFeatures = new Dictionary<int, double[]>();
            FabricManager.KarbelFeatures = new Dictionary<int, double[]>();
            FabricManager.MontiFeatures = new Dictionary<int, double[]>();

            foreach (DataRow dr in FabricManager.ProductsKarbel.Rows)
            {
                int ProductId = (int)dr["ProductId"];
                
                bool isKarbel = dr["FileName"].ToString() == "K";   //.ToLower().Contains("karbel_");
                
                List<double> doubles = new List<double>();

                for (int i = 0; i < 47; i++)
                {
                    string colName = "F" + i.ToString().PadLeft(2, '0');

                    if (dr[colName] == DBNull.Value)
                        doubles.Add(0);
                    else
                        doubles.Add((double)dr[colName]);
                }
                if (isKarbel)
                    FabricManager.KarbelFeatures.Add(ProductId, doubles.ToArray());
                else
                    FabricManager.MontiFeatures.Add(ProductId, doubles.ToArray());
                
                FabricManager.AllFeatures.Add(ProductId, doubles.ToArray());
            }
        }

        public static DataTable GetUpdates()
        {
            //son serialize'dan sonra eklenen/değişen kumaş resimlerini al
            DateTime lastModified = GetLastModified();

            DataSet NewPhotos = Data.DM.ExecuteDataSet("GetThumbnails", lastModified);
            DataTable dtKarbel = NewPhotos.Tables[0];
            return dtKarbel;
        }

        [Serializable]
        public class FM
        {
            public int ProductId;
            public byte[] Thumbnail;
            public string FileName;
            //public decimal Hue;
            public DateTime ModifiedOn;
            public double F00;
            public double F01;
            public double F02;
            public double F03;
            public double F04;
            public double F05;
            public double F06;
            public double F07;
            public double F08;
            public double F09;
            public double F10;
            public double F11;
            public double F12;
            public double F13;
            public double F14;
            public double F15;
            public double F16;
            public double F17;
            public double F18;
            public double F19;
            public double F20;
            public double F21;
            public double F22;
            public double F23;
            public double F24;
            public double F25;
            public double F26;
            public double F27;
            public double F28;
            public double F29;
            public double F30;
            public double F31;
            public double F32;
            public double F33;
            public double F34;
            public double F35;
            public double F36;
            public double F37;
            public double F38;
            public double F39;
            public double F40;
            public double F41;
            public double F42;
            public double F43;
            public double F44;
            public double F45;
            public double F46;
        }

        public static void Serialize()
        {
            List<FM> FRs = new List<FM>();
            foreach (DataRow dr in ProductsKarbel.Rows)
            {
                FM fr = new FM();
                fr.ProductId = (int)dr["ProductId"];
                fr.Thumbnail = (byte[])dr["Thumbnail"];
                fr.ModifiedOn = (DateTime)dr["ModifiedOn"];
                fr.FileName = (string)dr["FileName"];
                //fr.Hue = (decimal)dr["Hue"];
                fr.F00 = (double)dr["F00"];
                fr.F01 = (double)dr["F01"];
                fr.F02 = (double)dr["F02"];
                fr.F03 = (double)dr["F03"];
                fr.F04 = (double)dr["F04"];
                fr.F05 = (double)dr["F05"];
                fr.F06 = (double)dr["F06"];
                fr.F07 = (double)dr["F07"];
                fr.F08 = (double)dr["F08"];
                fr.F09 = (double)dr["F09"];
                fr.F10 = (double)dr["F10"];
                fr.F11 = (double)dr["F11"];
                fr.F12 = (double)dr["F12"];
                fr.F13 = (double)dr["F13"];
                fr.F14 = (double)dr["F14"];
                fr.F15 = (double)dr["F15"];
                fr.F16 = (double)dr["F16"];
                fr.F17 = (double)dr["F17"];
                fr.F18 = (double)dr["F18"];
                fr.F19 = (double)dr["F19"];
                fr.F20 = (double)dr["F20"];
                fr.F21 = (double)dr["F21"];
                fr.F22 = (double)dr["F22"];
                fr.F23 = (double)dr["F23"];
                fr.F24 = (double)dr["F24"];
                fr.F25 = (double)dr["F25"];
                fr.F26 = (double)dr["F26"];
                fr.F27 = (double)dr["F27"];
                fr.F28 = (double)dr["F28"];
                fr.F29 = (double)dr["F29"];
                fr.F30 = (double)dr["F30"];
                fr.F31 = (double)dr["F31"];
                fr.F32 = (double)dr["F32"];
                fr.F33 = (double)dr["F33"];
                fr.F34 = (double)dr["F34"];
                fr.F35 = (double)dr["F35"];
                fr.F36 = (double)dr["F36"];
                fr.F37 = (double)dr["F37"];
                fr.F38 = (double)dr["F38"];
                fr.F39 = (double)dr["F39"];
                fr.F40 = (double)dr["F40"];
                fr.F41 = (double)dr["F41"];
                fr.F42 = (double)dr["F42"];
                fr.F43 = (double)dr["F43"];
                fr.F44 = (double)dr["F44"];
                fr.F45 = (double)dr["F45"];
                fr.F46 = (double)dr["F46"];

                FRs.Add(fr);
            }

            BinaryFormatter formatter = new BinaryFormatter();
            
            using ( FileStream fileStream = new FileStream(FabricManagerFileName , FileMode.Create, FileAccess.Write))
            {
                formatter.Serialize(fileStream, FRs.ToArray() );
            }
        }

        public static DataTable GetLocalPhotos()
        {
            FileInfo fi = new FileInfo(FabricManagerFileName);

            BinaryFormatter formatter = new BinaryFormatter();

            DataTable dt = new DataTable();

            if (fi.Exists)
            {
                FM[] FRs;
                using (FileStream fileStream = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read))
                    FRs = (FM[])formatter.Deserialize(fileStream);

                dt.Columns.Add("ProductId",typeof(int));
                dt.Columns.Add("Thumbnail", typeof(byte[]));
                dt.Columns.Add("FileName", typeof(string));
                //dt.Columns.Add("Hue", typeof(decimal));
                dt.Columns.Add("ModifiedOn", typeof(DateTime));                
                dt.Columns.Add("F00",typeof(double));
                dt.Columns.Add("F01",typeof(double));
                dt.Columns.Add("F02",typeof(double));
                dt.Columns.Add("F03",typeof(double));
                dt.Columns.Add("F04",typeof(double));
                dt.Columns.Add("F05",typeof(double));
                dt.Columns.Add("F06",typeof(double));
                dt.Columns.Add("F07",typeof(double));
                dt.Columns.Add("F08",typeof(double));
                dt.Columns.Add("F09",typeof(double));
                dt.Columns.Add("F10",typeof(double));
                dt.Columns.Add("F11",typeof(double));
                dt.Columns.Add("F12",typeof(double));
                dt.Columns.Add("F13",typeof(double));
                dt.Columns.Add("F14",typeof(double));
                dt.Columns.Add("F15",typeof(double));
                dt.Columns.Add("F16",typeof(double));
                dt.Columns.Add("F17",typeof(double));
                dt.Columns.Add("F18",typeof(double));
                dt.Columns.Add("F19",typeof(double));
                dt.Columns.Add("F20",typeof(double));
                dt.Columns.Add("F21",typeof(double));
                dt.Columns.Add("F22",typeof(double));
                dt.Columns.Add("F23",typeof(double));
                dt.Columns.Add("F24",typeof(double));
                dt.Columns.Add("F25",typeof(double));
                dt.Columns.Add("F26",typeof(double));
                dt.Columns.Add("F27",typeof(double));
                dt.Columns.Add("F28",typeof(double));
                dt.Columns.Add("F29",typeof(double));
                dt.Columns.Add("F30",typeof(double));
                dt.Columns.Add("F31",typeof(double));
                dt.Columns.Add("F32",typeof(double));
                dt.Columns.Add("F33",typeof(double));
                dt.Columns.Add("F34",typeof(double));
                dt.Columns.Add("F35",typeof(double));
                dt.Columns.Add("F36",typeof(double));
                dt.Columns.Add("F37",typeof(double));
                dt.Columns.Add("F38",typeof(double));
                dt.Columns.Add("F39",typeof(double));
                dt.Columns.Add("F40",typeof(double));
                dt.Columns.Add("F41",typeof(double));
                dt.Columns.Add("F42",typeof(double));
                dt.Columns.Add("F43",typeof(double));
                dt.Columns.Add("F44",typeof(double));
                dt.Columns.Add("F45",typeof(double));
                dt.Columns.Add("F46",typeof(double));

                foreach (FM fr in FRs)
                {
                    dt.Rows.Add(fr.ProductId, fr.Thumbnail, fr.FileName, fr.ModifiedOn,fr.F00,fr.F01,fr.F02,fr.F03,fr.F04,fr.F05,fr.F06,fr.F07,fr.F08,
                        fr.F09,fr.F10,fr.F11,fr.F12,fr.F13,fr.F14,fr.F15,fr.F16,fr.F17,fr.F18,fr.F19,fr.F20,fr.F21,fr.F22,fr.F23,fr.F24,fr.F25,fr.F26,
                        fr.F27,fr.F28,fr.F29,fr.F30,fr.F31,fr.F32,fr.F33,fr.F34,fr.F35,fr.F36,fr.F37,fr.F38,fr.F39,fr.F40,fr.F41,fr.F42,fr.F43,fr.F44,
                        fr.F45,fr.F46);
                }
            }
            else
            {
                dt.Columns.Add("ProductId", typeof(int));
                dt.Columns.Add("ModifiedOn", typeof(DateTime));
            }

            dt.Columns.Add("Middle", typeof(byte[]));
            dt.PrimaryKey = new DataColumn[] { dt.Columns["ProductId"] };
            return dt;
        }

        public static DateTime GetLastModified()
        {
            DateTime LastModifiedOn = new DateTime(2000, 1, 1);
            foreach (DataRow dr in ProductsKarbel.Rows)
                if ((DateTime)dr["ModifiedOn"] > LastModifiedOn)
                    LastModifiedOn = (DateTime)dr["ModifiedOn"];
            return LastModifiedOn;
        }

        public static DataTable GetSimilars(int ProductId)
        {
            if (!AppSession.MainForm.chkKarbel.Checked && !AppSession.MainForm.chkMonti.Checked)
            {
                AppSession.MainForm.chkKarbel.Checked = true;
                AppSession.MainForm.chkMonti.Checked = true;
            }

            List<int> result = new List<int>();

            double[] FeatureVector = AllFeatures[ProductId];

            Dictionary<int, double[]> baseList = new Dictionary<int, double[]>();

            if (AppSession.MainForm.chkKarbel.Checked && !AppSession.MainForm.chkMonti.Checked)
                baseList = KarbelFeatures;

            else if (!AppSession.MainForm.chkKarbel.Checked && AppSession.MainForm.chkMonti.Checked)
                baseList = MontiFeatures;

            else if (AppSession.MainForm.chkKarbel.Checked && AppSession.MainForm.chkMonti.Checked)
                baseList = AllFeatures;

            int count = AppSession.MainForm.beCount.EditValue.ToIntZero();
                        
            Paranavision pv = new Paranavision();
            Dictionary<int, double> paranaResult = pv.GetSimilarsTopN(FeatureVector, baseList, count);
            result = paranaResult.Keys.ToList();

            List<int> missing = new List<int>();

            foreach (int id in result)
            {
                DataRow dr =  ProductsKarbel.Rows.Find(id);
                if (dr["Middle"] == DBNull.Value)
                    missing.Add((int)dr["ProductId"]);
            }

            string missingIds = string.Join(",", missing);
            if (missingIds != "")
            {
                DataTable dtMiddle = Data.DM.ExecuteDataTable("GetMiddles", missingIds);
                ProductsKarbel.Merge(dtMiddle);
            }

            DataTable dtResult = new DataTable();
            dtResult.Columns.Add("ProductId", typeof(int));
            dtResult.Columns.Add("FileName", typeof(string));
            dtResult.Columns.Add("Middle", typeof(byte[]));
            //dtResult.Columns.Add("Hue", typeof(decimal));
            
            foreach (int id in result)
            {
                DataRow dr = ProductsKarbel.Rows.Find(id);
                dtResult.Rows.Add(dr["ProductId"], dr["FileName"], dr["Middle"]);
            }

            return dtResult;
        }
   

        public static RepositoryItemPictureEdit GetPhotoRI()
        {
            RepositoryItemPictureEdit ri = new RepositoryItemPictureEdit();
            ri.SizeMode = PictureSizeMode.Zoom;
            ri.NullText = " ";
            ri.Padding = new Padding(-1);
            ri.PictureStoreMode = PictureStoreMode.ByteArray;
            return ri;
        }

        private static Dictionary<int, byte[]> biggers = new Dictionary<int, byte[]>();
        public static System.Drawing.Image GetBiggerImage(int ProductId)
        {
            Bitmap bitmap = null;
            if (!biggers.ContainsKey(ProductId))
            {
                byte[] img = (byte[])Data.DM.ExecuteScalar("GetBiggerImage", ProductId);
                biggers.Add(ProductId, img);
            }

            using (MemoryStream ms = new MemoryStream(biggers[ProductId]))
                bitmap = (Bitmap)Image.FromStream(ms);

            return bitmap;
        }
    }
}